package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.leanring.LearningRecordFormDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.ForbiddenException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-12-07
 */
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    @Autowired
    private ILearningLessonService lessonService;

    /**
     * 根据课程id查询学习记录
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        if (courseId == null) {
            throw new ForbiddenException("课程id不能为空");
        }
        //从用户学习表中查询
        LearningLesson learningLesson = lessonService.<LearningLesson>lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .one();
        if (learningLesson == null) {
            throw new ForbiddenException("课程不存在");
        }
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        learningLessonDTO.setId(learningLesson.getId());
        learningLessonDTO.setLatestSectionId(learningLesson.getLatestSectionId());
        //从学习记录表中查询
        List<LearningRecord> recordListlist = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, learningLesson.getId())
                .eq(LearningRecord::getUserId, UserContext.getUser())
                .orderByAsc(LearningRecord::getCreateTime)
                .list();
        if (recordListlist == null) {
            return learningLessonDTO;
        }
        learningLessonDTO.setRecords(BeanUtils.copyList(recordListlist, LearningRecordDTO.class));
        return learningLessonDTO;
    }

    /**
     * 提交学习记录
     *
     * @param recordDTO
     */
    @Override
//    @Async("taskExecutor")// 开启线程池异步处理
    @Transactional
    public void addLearningRecord(LearningRecordFormDTO recordDTO) {

        //1.判断参数
        if (ObjectUtils.isEmpty(recordDTO)) {
            throw new ForbiddenException("参数不能为空");
        }
        Long userId = UserContext.getUser();
        boolean finished = false;
        //2.判断是否为考试
        if (recordDTO.getSectionType().equals(SectionType.EXAM.getValue())) {
            //2.1.如果是考试
            finished = handleExamRecord(userId, recordDTO);
        } else {
            // 2.2如果是视频 (如果有看完的小节返回true,如果没有flase)
            finished = handleVideoRecord(userId, recordDTO);
        }
        if (!finished) {
            // 没有新学完的小节，无需更新课表中的学习进度
            return;
        }
        //更新课表状态(小节数)
        handleLearningLessonsChanges(recordDTO, finished);

    }

    @Autowired
    private CourseClient courseClient;
    @Autowired
    private LearningRecordDelayTaskHandler taskHandler;

    /**
     * 处理完学习记录后更新课表状态
     *
     * @param recordDTO
     * @param finished
     */
    private void handleLearningLessonsChanges(LearningRecordFormDTO recordDTO, boolean finished) {

        // 1.查询课表
        LearningLesson lesson = lessonService.getById(recordDTO.getLessonId());
        if (lesson == null) {
            throw new BizIllegalException("课程不存在，无法更新数据！");
        }
        // 2.判断是否有新的完成小节
        boolean allLearned = false;

        // 3.如果有新完成的小节，则需要查询课程数据
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null) {
            throw new BizIllegalException("课程不存在，无法更新数据！");
        }
        // 4.比较课程是否全部学完：已学习小节 >= 课程总小节
        allLearned = lesson.getLearnedSections() + 1 >= cInfo.getSectionNum();

        // 5.更新课表
        lessonService.lambdaUpdate()
                .set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .set(allLearned, LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                .set(allLearned, LearningLesson::getLatestSectionId, recordDTO.getSectionId())
                .set(allLearned, LearningLesson::getLatestLearnTime, recordDTO.getCommitTime())
//                .set(allLearned, LearningLesson::getFinishTime, LocalDateTime.now())
                .setSql(finished, "learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId, lesson.getId())
                .update();
    }

    /**
     * 处理提交的学习记录是视频
     *
     * @param userId
     * @param recordDTO
     * @return
     */

    private Boolean handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {
        //查询学习记录是否存在(上次的视频没看完)
        LearningRecord oldRecord = queryOldRecord( recordDTO.getLessonId(), recordDTO.getSectionId());
        if (ObjectUtils.isEmpty(oldRecord)) {
            //更新学习记录
            LearningRecord learningRecord = BeanUtils.copyBean(recordDTO, LearningRecord.class);
            learningRecord.setUserId(userId);
            learningRecord.setMoment(0);
            boolean save = save(learningRecord);
            if (!save) {
                throw new ForbiddenException("保存学习记录失败");
            }
            return false;
        }
        //判断是否第一次就学完了
        boolean finished = !oldRecord.getFinished() && recordDTO.getMoment() * 2 >= recordDTO.getDuration();
        //没学完添加缓存,延迟任务
        if (!finished) {
            LearningRecord record = new LearningRecord();
            record.setLessonId(recordDTO.getLessonId());
            record.setSectionId(recordDTO.getSectionId());
            record.setMoment(recordDTO.getMoment());
            record.setId(oldRecord.getId());
            record.setFinished(oldRecord.getFinished());
            //添加延迟任务
            taskHandler.addLearningRecordTask(record);
            return false;
        }
        boolean success = lambdaUpdate()
//                .set(LearningRecord::getMoment, recordDTO.getMoment())
                .set(finished, LearningRecord::getFinished, true)
                .set(finished, LearningRecord::getFinishTime, recordDTO.getCommitTime())
                .eq(LearningRecord::getId, oldRecord.getId())
                .update();
        if (!success) {
            throw new ForbiddenException("更新学习记录失败");
        }
        // 4.3.清理缓存
        taskHandler.cleanRecordCache(recordDTO.getLessonId(), recordDTO.getSectionId());

        return finished;
    }

    /**
     * 查询久的学习记录
     *
     * @param lessonId
     * @param sectionId
     */
    private LearningRecord queryOldRecord( Long lessonId, Long sectionId) {
        if (ObjectUtils.isEmpty(lessonId) || ObjectUtils.isEmpty(sectionId)) {
            throw new ForbiddenException("参数不能为空");
        }
        // 1.查询缓存
        LearningRecord record = taskHandler.readRecordCache(lessonId, sectionId);
        // 2.如果命中，直接返回
        if (ObjectUtils.isNotEmpty(record)) {
            return record;
        }
        //没有命中,查询数据库
        LearningRecord one = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if (ObjectUtils.isEmpty(one)){
            return null;
        }
        //写入缓存
        taskHandler.wirteRecondCache(one);
        return one;
    }


    /**
     * 处理提交的学习记录是考试
     *
     * @param userId
     * @param recordDTO
     * @return
     */
    private Boolean handleExamRecord(Long userId, LearningRecordFormDTO recordDTO) {

        LearningRecord learningRecord = BeanUtils.copyBean(recordDTO, LearningRecord.class);
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(recordDTO.getCommitTime());

        boolean save = save(learningRecord);
        if (!save) {
            throw new ForbiddenException("保存学习记录失败");
        }
        return save;
    }


}
